package com.zk;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


/**
 * 分布式配置中心demo
 * 对于 zookeeper 节点的 增加 删除 修改 查询等。
 * @author zzx
 *
 */
@Service
@Component
public class ZooKeeperProSync {
	private static final Logger logger = LoggerFactory.getLogger(ZooKeeperProSync.class);
	
	private static CountDownLatch connectedSemaphore = new CountDownLatch(1);
    //private static ZooKeeper zk = null;
    private static Stat stat = new Stat();
    
    //注入 zookeeper的初始化链接
    @Autowired
    private ZooKeeper zookeeper;
    
    
    
    public void getZk(String path) throws InterruptedException, IOException, KeeperException {
    	//zookeeper配置数据存放路径
       // String path = "/username";
        //连接zookeeper并且注册一个默认的监听器
        //zk = new ZooKeeper("10.10.10.25:2181", 5000, //
        //等待zk连接成功的通知
        connectedSemaphore.await();
        //获取path目录节点的配置数据，并注册默认的监听器
        logger.info(new String(zookeeper.getData(path, true, stat)));
 
        Thread.sleep(Integer.MAX_VALUE);
    }
    /**
     * 	新增一个 节点，
     * @param path 节点名称
     * @param data 节点内容
     * @throws IOException
     */
    public void createZk(String path,String data) throws IOException {    	
    	logger.info("创建节点***开始");
    	try {
    		//getZookeeper();
    		zookeeper.create(path,data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
        } catch (Exception e) {
        	logger.info("【创建持久化节点异常】{},{},{}",e);
        }
    	
    	logger.info("创建节点***结束");
    }
    /**
     * 	修改持久化节点
     * @param path 节点路径
     * @param data 节点名称
     */
    public void updateNode(String path, String data){
        try {
            //zk的数据版本是从0开始计数的。如果客户端传入的是-1，则表示zk服务器需要基于最新的数据进行更新。如果对zk的数据节点的更新操作没有原子性要求则可以使用-1.
            //version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
        	
        	zookeeper.setData(path,data.getBytes(),-1);
          
        } catch (Exception e) {
            logger.error("【修改持久化节点异常】{},{},{}",path,data,e);
        }
    }
    /**
     * 	删除节点
     * @param path
     */
    public void delete(String path) {
    	try {
    		//version参数指定要更新的数据的版本, 如果version和真实的版本不同, 更新操作将失败. 指定version为-1则忽略版本检查
    		zookeeper.delete(path,-1);
		}  catch (Exception e) {
		
			e.printStackTrace();
		}
    }
    
    /**
     	* 判断指定节点是否存在
     * @param path
     * @param needWatch  指定是否复用zookeeper中默认的Watcher
     * @return
     */
    public Stat exists(String path, boolean needWatch){
        try {
            return zookeeper.exists(path,needWatch);
        } catch (Exception e) {
            logger.error("【断指定节点是否存在异常】{},{}",path,e);
            return null;
        }
    }

    /**
	     *  检测结点是否存在 并设置监听事件
	     *      三种监听类型： 创建，删除，更新
     *
     * @param path
     * @param watcher  传入指定的监听类
     * @return
     */
    public Stat exists(String path,Watcher watcher ){
        try {
            return zookeeper.exists(path,watcher);
        } catch (Exception e) {
            logger.error("【断指定节点是否存在异常】{},{}",path,e);
            return null;
        }
    }
    
    /**
     * 	获取当前节点的子节点(不包含孙子节点)
     * @param path 父节点path
     */
   public List<String> getChildren(String path) throws KeeperException, InterruptedException{
	   
	   List<String> list = zookeeper.getChildren(path, false);
       return list;
   }

   /**
	*	 获取指定节点的值
    * @param path
    * @return
    */
   public  String getData(String path){
       try {
           if(exists(path,new WatcherApi()) == null) {
        	   return "节点不存在";
           }
    	   Stat stat=new Stat();
           byte[] bytes=zookeeper.getData(path,new WatcherApi(),stat);
           return  new String(bytes);
       }catch (Exception e){
           e.printStackTrace();
           return  null;
       }
   }
   
//	@Override
//	public void process(WatchedEvent event) {
//		if (KeeperState.SyncConnected == event.getState()) {  //zk连接成功通知事件
//            if (EventType.None == event.getType() && null == event.getPath()) {
//                connectedSemaphore.countDown();
//            } else if (event.getType() == EventType.NodeDataChanged) {  //zk目录节点数据变化通知事件
//                try {
//                    System.out.println("配置已修改，新值为：" + new String(zookeeper.getData(event.getPath(), true, stat)));
//                } catch (Exception e) {
//                }
//            }
//        }
//
//		
//	}
	
}
